package models.parsers;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import models.BankStatement;
import models.HsbcCreditStatementExtraInfo;
import models.Transaction;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;

public class HsbcCreditParser extends BaseExcelParser {
    static Logger _logger = Logger.getLogger(HsbcCreditParser.class);

    private static final int COLUMN_DATE = 0;
    private static final int COLUMN_LABEL = 1;
    private static final int COLUMN_AMOUNT = 3;

    private int _creditLimitRow = -1;

    public HsbcCreditParser(String filename) {
        super(filename);
    }

    public HsbcCreditParser(InputStream inputstream) {
        super(inputstream);
    }

    @Override
    public BankStatement getStatement() {
        return super.getStatement();
    }

    public List<Transaction> getTransactionsFromSheet(HSSFSheet sheet) {

        List<Transaction> transactions = new ArrayList<Transaction>();

        int rows = sheet.getLastRowNum();
        int initRow = findTransactionsHeaderRow(sheet);
        for (int r = initRow + 1; r < rows; r++) {
            HSSFRow row = sheet.getRow(r);
            if (row == null) {
                break;
            }

            int initCol = 4;

            String dateString = getStringValue(row.getCell(initCol + COLUMN_DATE));
            String label = getStringValue(row.getCell(initCol + COLUMN_LABEL));
            String amountString = getStringValue(row.getCell(initCol + COLUMN_AMOUNT));

            if (StringUtils.isBlank(dateString) && StringUtils.isBlank(label) && StringUtils.isBlank(amountString)) {
                break;
            }

            BigDecimal amount = parseAmount(amountString);
            Date date = parseDate(dateString);

            transactions.add(new Transaction(null, null, date, label, amount));
        }

        return transactions;
    }

    public boolean parse() {
        setAlreadyParsed(false);
        try {
            workbook = readFile();

            HSSFSheet sheet = workbook.getSheetAt(0);
            List<Transaction> transactions = getTransactionsFromSheet(sheet);
            BankStatement statment = new BankStatement(null, transactions, null, getBegin(sheet), getEnd(sheet));
            statment.balance = getCurrentBalance(sheet);
            statment.hsbcCreditStatementExtraInfo = new HsbcCreditStatementExtraInfo();
            statment.hsbcCreditStatementExtraInfo.balanceAtEndOfCycle = getBalanceAtEndOfCycle(sheet);
            statment.hsbcCreditStatementExtraInfo.cashDrawbacks = getCashDrawbacks(sheet);
            statment.hsbcCreditStatementExtraInfo.creditAvailable = getCreditAvailable(sheet);
            statment.hsbcCreditStatementExtraInfo.creditCardNumber = getCreditCardNumber(sheet);
            statment.hsbcCreditStatementExtraInfo.creditLimit = getCreditLimit(sheet);
            statment.hsbcCreditStatementExtraInfo.cutoffDate = getCutoffDate(sheet);
            statment.hsbcCreditStatementExtraInfo.daysInCycle = getDaysInCycle(sheet);
            statment.hsbcCreditStatementExtraInfo.interestAmount = getInterestAmount(sheet);
            statment.hsbcCreditStatementExtraInfo.miles = getMiles(sheet);
            statment.hsbcCreditStatementExtraInfo.minimumPayment = getMinimumPayment(sheet);
            statment.hsbcCreditStatementExtraInfo.newCharges = getNewCharges(sheet);
            statment.hsbcCreditStatementExtraInfo.payBefore = getPayBefore(sheet);
            statment.hsbcCreditStatementExtraInfo.paymentAndCredits = getPaymentAndCredits(sheet);
            statment.hsbcCreditStatementExtraInfo.paymentWithoutInterests = getPaymentWithoutInterest(sheet);
            setStatement(statment);
            setAlreadyParsed(true);
        } catch (IOException e) {
            _logger.error(e);
        }
        return alreadyParsed();
    }

    public Date getEnd(HSSFSheet sheet) {
        String billingCycle = getBillingCycle(sheet);

        return parseDate(StringUtils.split(billingCycle, "-")[1]);
    }

    public Date getBegin(HSSFSheet sheet) {
        String billingCycle = getBillingCycle(sheet);

        return parseDate(StringUtils.split(billingCycle, "-")[0]);
    }

    public String getBillingCycle(HSSFSheet sheet) {

        return getStringValueAt(sheet, getRowBillingCycle(), getColBillingCycle());
    }

    private int getRowBillingCycle() {
        return 5;
    }

    private int getColBillingCycle() {
        return 4;
    }

    public int findTransactionsHeaderRow(HSSFSheet sheet) {

        return findRowWithText(sheet, "Fecha de transacción");
    }

    public String getCreditCardNumber(HSSFSheet sheet) {

        return getStringValueAt(sheet, 5, 3);
    }

    public BigDecimal getCreditLimit(HSSFSheet sheet) {
        return getBigDecimalAt(sheet, getCreditLimitRow(sheet), getCreditLimitCellNum(sheet));
    }

    private int getCreditLimitRow(HSSFSheet sheet) {
        if (_creditLimitRow < 0) {
            _creditLimitRow = findRowWithText(sheet, "Límite de crédito:");
        }
        _logger.debug("_creditLimitRow  =" + _creditLimitRow);

        return _creditLimitRow;
    }

    private int getCreditLimitCellNum(HSSFSheet sheet) {
        return 5;
    }

    public BigDecimal getCreditAvailable(HSSFSheet sheet) {
        return getBigDecimalAt(sheet, getCreditAvailableRow(sheet), getCreditAvailableCellNum());
    }

    private int getCreditAvailableRow(HSSFSheet sheet) {
        return getCreditLimitRow(sheet);
    }

    private int getCreditAvailableCellNum() {
        return 7;
    }

    public Date getCutoffDate(HSSFSheet sheet) {
        return getDateAt(sheet, getCutoffDateRow(sheet), getCutoffDateCellNum());
    }

    private int getCutoffDateRow(HSSFSheet sheet) {
        return getCreditLimitRow(sheet) + 1;
    }

    private int getCutoffDateCellNum() {
        return 5;
    }

    public int getMiles(HSSFSheet sheet) {
        return getIntegerAt(sheet, getMilesRow(sheet), getMilesCellNum());
    }

    private int getMilesCellNum() {
        return 7;
    }

    private int getMilesRow(HSSFSheet sheet) {
        return getCreditLimitRow(sheet) + 1;
    }

    public int getDaysInCycle(HSSFSheet sheet) {
        return getIntegerAt(sheet, getDaysInCycleRow(sheet), getDaysInCycleCellNum());
    }

    private int getDaysInCycleRow(HSSFSheet sheet) {
        return getCreditLimitRow(sheet) + 2;
    }

    private int getDaysInCycleCellNum() {
        return 5;
    }

    public Date getPayBefore(HSSFSheet sheet) {
        return getDateAt(sheet, 5, 5);
    }

    public BigDecimal getMinimumPayment(HSSFSheet sheet) {
        return getBigDecimalAt(sheet, 5, 6);
    }

    public BigDecimal getPaymentWithoutInterest(HSSFSheet sheet) {
        return getBigDecimalAt(sheet, 5, 7);
    }

    public BigDecimal getCurrentBalance(HSSFSheet sheet) {
        return getBigDecimalAt(sheet, 5, 8);
    }

    public BigDecimal getBalanceAtEndOfCycle(HSSFSheet sheet) {
        return getBigDecimalAt(sheet, 8, 3);
    }

    public BigDecimal getNewCharges(HSSFSheet sheet) {
        return getBigDecimalAt(sheet, 8, 4);
    }

    public BigDecimal getPaymentAndCredits(HSSFSheet sheet) {
        return getBigDecimalAt(sheet, 8, 5);
    }

    public BigDecimal getCashDrawbacks(HSSFSheet sheet) {
        return getBigDecimalAt(sheet, 8, 6);
    }

    public BigDecimal getInterestAmount(HSSFSheet sheet) {
        return getBigDecimalAt(sheet, 8, 7);
    }
}
